#pragma once

#include <iostream>
#include <string>
#include <cstdlib>
#include <functional>
#include <cassert>
#include <sys/epoll.h>

#include "Sock.hpp"
#include "Log.hpp"

using namespace std;

class EpollServer
{
public:
    static const int gsize = 128;
    static const int num = 256;
    using func_t = function<int(int)>;

public:
    EpollServer(uint16_t port, func_t func) : port_(port), listensock_(-1), epfd_(-1), func_(func)
    {
    }
    void InitEpollServer()
    {
        listensock_ = Sock::Socket();
        Sock::Bind(listensock_, port_);
        Sock::Listen(listensock_);

        // 这里直接使用原生接口
        epfd_ = epoll_create(gsize);
        if (epfd_ < 0)
        {
            logMessage(FATAL, "%d:%s", errno, strerror(errno));
            exit(3);
        }

        logMessage(DEBUG, "创建监听套接字成功: %d", listensock_);
        logMessage(DEBUG, "创建epoll成功: %d", epfd_);
    }

    void HandlerEvents(struct epoll_event revs[], int n)
    {
        for (int i = 0; i < n; i++)
        {
            int sock = revs[i].data.fd;
            uint32_t revent = revs[i].events;
            if (revent & EPOLLIN) // 读事件就绪
            {
                if (sock == listensock_)
                {
                    string clientip;
                    uint16_t clientport = 0;
                    // 监听socket就绪, 获取新链接
                    int sockfd = Sock::Accept(listensock_, &clientip, &clientport);
                    if (sockfd < 0)
                    {
                        logMessage(FATAL, "%d:%s", errno, strerror(errno));
                        continue;
                    }
                    // 托管给epoll
                    struct epoll_event ev;
                    ev.events = EPOLLIN;
                    ev.data.fd = sockfd;
                    int n = epoll_ctl(epfd_, EPOLL_CTL_ADD, sockfd, &ev);
                    assert(n == 0);
                    (void)n;
                }
                else
                {
                    // 普通socket就绪，进行数据INPUT
                    // bug
                    int n = func_(sock);
                    if (n == 0 || n < 0)
                    {
                        // 先移除，在关闭
                        int x = epoll_ctl(epfd_, EPOLL_CTL_DEL, sock, nullptr);
                        assert(x == 0);
                        (void)x;
                        logMessage(DEBUG, "client quit: %d", sock);
                        close(sock);
                    }
                }
            }
            else
            {
            }
        }
    }

    void Run()
    {
        // 1. 先添加listensock_
        struct epoll_event ev;
        ev.events = EPOLLIN;
        ev.data.fd = listensock_;
        int n = epoll_ctl(epfd_, EPOLL_CTL_ADD, listensock_, &ev);
        assert(n == 0);
        (void)n;

        struct epoll_event revs[num];
        int timeout = 10000;
        while (true)
        {
            // 关于n：就绪的fd的个数，只需要进行将底层的就绪队列中的节点，依次从0下标放入revs中即可！
            int n = epoll_wait(epfd_, revs, num, timeout);
            switch (n)
            {
            case 0:
                cout << "time out ... : " << (unsigned long)time(nullptr) << endl;
                break;
            case -1:
                cerr << errno << " : " << strerror(errno) << endl;
                break;
            default:
                HandlerEvents(revs, n);
                break;
            }
        }
    }
    ~EpollServer()
    {
        if (listensock_ != -1)
            close(listensock_);
        if (epfd_ != -1)
            close(epfd_);
    }

private:
    int listensock_;
    int epfd_;
    uint16_t port_;
    func_t func_;
};